import tensorflow as tf

var1 = tf.Variable(1., name='first_var')
print('I am var1: ', var1.name)
var1 = tf.Variable(2., name='first_var')
print('I am var1 too: ', var1.name)
var2 = tf.Variable(3.)
print('I am var2: ', var2.name)
var2 = tf.Variable(4.)
print('I am var2 too: ', var2.name)

# I am var1:  first_var:0
# I am var1 too:  first_var_1:0
# I am var2:  Variable:0
# I am var2 too:  Variable_1:0


# tf.get_variable()中形参 name 必须指定
get_var1 = tf.get_variable(name='gv', shape=[])
print('I am get_var1: ', get_var1.name)
# get_var1 = tf.get_variable(name='gv', shape=[])
# print('I am get_var1 too, but I will cause a error: ', get_var1.name)

# I am get_var1:  gv:0
# Traceback (most recent call last):
# ValueError: Variable gv already exists, disallowed. Did you mean to set reuse=True
# or reuse=tf.AUTO_REUSE in VarScope? Originally defined at:
#     get_var1 = tf.get_variable(name='gv', shape=[])

# 既然 tf.get_variable() 不允许重名，那怎么办？ 放心吧，总会有办法解决的。
# 要解决这个问题，就要引入 tf.variable_scope() 隔离开 tf.get_variable() 定义的同名变量就可以了
# 看个例子

with tf.variable_scope('vs1'):
    get_var1 = tf.get_variable(name='getVar', shape=[])

with tf.variable_scope('vs2'):
    get_var2 = tf.get_variable(name='getVar', shape=[])

with tf.variable_scope('vs3'):
    get_var3 = tf.get_variable(name='getVar', shape=[])
    with tf.variable_scope('vs4'):
        get_var4 = tf.get_variable(name='getVar', shape=[])


print('get_var1', get_var1.name)  # get_var1 vs1/getVar:0
print('get_var2', get_var2.name)  # get_var2 vs2/getVar:0
print('get_var3', get_var3.name)  # get_var3 vs3/getVar:0
print('get_var4', get_var4.name)  # get_var4 vs3/vs4/getVar:0

# 同名的变量在程序中共存，完美解决这个问题
# 在看一些代码的时候, 经常会看到 tf.name_scope() 和 tf.variable_scope(), 那他们两个到底啥关系呢？

with tf.name_scope('ns'):
    var1 = tf.Variable(1., tf.float32)
    with tf.variable_scope('vs'):
        var2 = tf.Variable(2., tf.float32)
        get_var = tf.get_variable(name='gv', shape=[])
print('var1', var1.name)  # var1 ns/Variable:0
print('var2', var2.name)  # var2 ns/vs/Variable:0
print('get_var', get_var.name)  # get_var vs/gv:0

# 从上面的 get_var 的作用范围，可以看出 tf.get_variable() 不受 tf.name_scope() 的控制

# 下面就来看看共享变量怎么操作的
# tf.variable_scope() 中有一个 reuse 的参数，表示使用已经定义过的变量，当然如果使用的变量未定义，就会报错...

with tf.variable_scope('vs5'):
    get_var5 = tf.get_variable(name='getVar_reuse', shape=[])

with tf.variable_scope('vs5', reuse=True):
    get_var6 = tf.get_variable(name='getVar_reuse', shape=[])
    # get_var7 = tf.get_variable(name='getVar_unknown', shape=[])

print('get_var5', get_var5.name)  # get_var5 vs5/getVar_reuse:0
print('get_var6', get_var6.name)  # get_var6 vs5/getVar_reuse:0
# print('get_var7', get_var7.name)  # 报错

# tf.variable_scope() 和 tf.get_variable() 的初始化变量功能
with tf.variable_scope('vs6', initializer=tf.constant_initializer(1.)):
    get_var8 = tf.get_variable(name='getVar8', shape=[1])
    with tf.variable_scope('vs7'):
        get_var9 = tf.get_variable(name='getVar9', shape=[1])
        get_var10 = tf.get_variable(name='getVar10', shape=[1], initializer=tf.constant_initializer(2.))
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print('get_var8 = ', get_var8.eval())
    print('get_var9 = ', get_var9.eval())
    print('get_var10 = ', get_var10.eval())

# get_var8 =  [1.]
# get_var9 =  [1.]
# get_var10 =  [2.]

# 看看下面的一个例子，怎么使内层变量使用另一个作用于的变量
with tf.variable_scope('vs8') as vs8:
    get_var11 = tf.get_variable(name='getVar11', shape=[])

print('vs8: ', vs8.name)             # vs8: vs8
print('getVar11', get_var11.name)  # getVar11 vs8/getVar11:0

with tf.variable_scope('vs9'):
    get_var12 = tf.get_variable(name='getVar12', shape=[])
    with tf.variable_scope(vs8, reuse=True) as vs8_:
        get_var13 = tf.get_variable(name='getVar11', shape=[])

print('vs8_: ', vs8.name)              # vs8_:  vs8
print('getVar12', get_var12.name)      # getVar12 vs9/getVar12:0
print('getVar13', get_var13.name)      # getVar13 vs8/getVar13:0


# tf.name_scope() 使用空字符串将作用域返回到顶层
with tf.variable_scope('vs10'):
    get_var14 = tf.get_variable(name='getVar14', shape=[])
    with tf.variable_scope('vs11'):
        get_var15 = tf.get_variable(name='getVar15', shape=[])
        with tf.name_scope(''):
            get_var16 = tf.Variable(1., name='getVar16')

        with tf.variable_scope(''):
            get_var17 = tf.get_variable(name='getVar17', shape=[])

print('getVar14', get_var14.name)
print('getVar15', get_var15.name)
print('getVar16', get_var16.name)
print('getVar17', get_var17.name)

# getVar14 vs10/getVar14:0
# getVar15 vs10/vs11/getVar15:0
# getVar16 getVar16:0
# getVar17 vs10/vs11//getVar17:0   # 中间多个空层
